package jogo;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import Cartas.Baralho;
import Cartas.Carta;
import Cartas.CartaComCor;
import Cartas.CartaNumerica;
import Cartas.ComprarDuas;
import Cartas.ComprarQuatro;
import Cartas.Coringa;
import Cartas.Inverter;
import Cartas.Pular;

public class Jogo {
	
	//especifica os tipos de jogadas que o jogador pode fazer
	public static int TIPO_JOGADA_EMPRILHAR = 0;
	public static int TIPO_JOGADA_DESAFIAR = 2;
	public static int TIPO_JOGADA_COMPRAR = 3;
	public static int TIPO_JOGADA_DESISTENCIA = 4;
	
	
	
	List <Jogador> jogadores;
	
	Baralho monteDisponivel;
	
	//cartas que j� foram utilizadas
	Baralho monteJogado;
	
	//cartas que s�o acumadas para passar para o jogador no caso dele n�o possuir carta boa para jogar
	//ou que ser� passada para o pr�ximo caso o atula jogue +2, ou +4.
	List <Carta> cartasAcumuladas;
	
	Carta cartaAmostra;
	Carta cartaJogadaAnterior;
	
	Jogador vencedor;
	Jogador jogadorAtual;
	Jogador jogadorAnterior;
	int indiceJogadorAtual;
	int indiceJogadorAnterior;
		
	//1 = hor�rio, -1 = anti-hor�rio
	int sentido = 1;
	
	
	public Jogo(List<Jogador> jogadores) {

		monteDisponivel = new Baralho(Baralho.COMPLETO);
		monteDisponivel.embaralhar();

		this.jogadores = jogadores;
		
		distribuirCartas();
		
		monteJogado = new Baralho(Baralho.VAZIO);
		cartasAcumuladas = new ArrayList<>();
		
		cartaAmostra = cartaInicial();
		
		jogadorAtual = jogadorInicial();

		sentido = 1;
	}
	
	/*####################################
	 * M�TODOS DE INICIALIZA��O DO JOGO
	 *####################################*/
	protected void distribuirCartas() {
		
		int quantidadeRodada = 0;
		
		//distribui 7 cartas para cada jogador
		while (quantidadeRodada < 7) {
			
			for (Jogador jogador: jogadores) {
				jogador.getBaralho().adicionaCarta(monteDisponivel.retirarCarta());	
			}
			quantidadeRodada++;
		}
	}
	
	
	protected Carta cartaInicial() {
		//pega a primeira carta do baralho
		Carta inicial = monteDisponivel.retirarCarta();
		
		//enquanto a carta for Coringa
		while (inicial.getClass() == Coringa.class || 
				inicial.getClass().getSuperclass() == Coringa.class) {
			//adicione ao final do baralho a carta Coringa
			monteDisponivel.adicionaCarta(inicial);
			//remova a primeira carta do baralho e a coloque como a carta a amostra para in�cio do jogo
			inicial = monteDisponivel.retirarCarta();
		}
		
		return inicial;
	}
	
	
	private Jogador jogadorInicial() {
		//escolhe-se 1 jogador aleat�rio
		Random indice = new Random();
		
		indiceJogadorAtual = indice.nextInt(jogadores.size());
		return jogadores.get(indiceJogadorAtual);
	}
	
	

	
	/*####################################
	 * M�TODOS DE INTERACAO DA JOGADA
	 *####################################*/
	
	
	public void realizarJogada(Jogador jogador, Carta carta, int tipoJogada) {
		if (tipoJogada == Jogo.TIPO_JOGADA_DESISTENCIA) {
			desistir(jogador);
		} else {
			if (jogadaEhValida(jogador, tipoJogada, carta)) {
				
				if (tipoJogada == Jogo.TIPO_JOGADA_DESAFIAR) {
					//verifica se o jogadorAnterior possuia carta jog�vel anterior a carta comprar4 que ele jogou
					if (jogadaIlegal(jogadorAnterior)) {
						jogadorAnterior.getBaralho().adicionaCartas(pegarCartasMonteDisponivel(4));
					} else {
						jogadorAtual.getBaralho().adicionaCartas(pegarCartasMonteDisponivel(2));
					}
					
				} else if (tipoJogada == Jogo.TIPO_JOGADA_COMPRAR) {
					
					jogadorAtual.getBaralho().adicionaCartas(pegarCartasMonteDisponivel(1));
					
				} else if (tipoJogada == Jogo.TIPO_JOGADA_EMPRILHAR) {
					efetuarAcao(carta);
				}
				
				jogadorAnterior = jogadorAtual;
				jogadorAtual = proximoJogador();
			}
		}
	}
	
	
	private Jogador verificarVencedor(Jogador jogador ) {
		if (jogador.getBaralho().estaVazio()) {
			return jogador;
		}
		return null;
	}
	
	protected List<Carta> pegarCartasMonteDisponivel(int quantidade) {
		
		List<Carta> acumulador = new ArrayList<>();
		
		for (int i = 0; i < quantidade; i++) {
			if (monteDisponivel.estaVazio()) {
				monteDisponivel = disponibilizarNovoMonte();
			} 
			acumulador.add(monteDisponivel.retirarCarta());
		}
		
		return acumulador;
	}
	
	
	protected Baralho disponibilizarNovoMonte() {
		monteJogado.embaralhar();
		monteJogado.embaralhar();
		Baralho novoMonte = monteJogado;
		
		monteJogado = new Baralho(Baralho.VAZIO);
		monteDisponivel = novoMonte;
		return novoMonte;
	}
	
	
	//verifica se:
	//o jogador possui a carta que está jogando, e se ela pode ser jogada
	//se o tipo da jogada for DASAFIAR, verifica se a carta a mostra é +4
	protected boolean jogadaEhValida(Jogador jogador, int tipoJogada, Carta carta) {
		if (jogador == jogadorAtual) {
			if (tipoJogada == Jogo.TIPO_JOGADA_DESAFIAR) {
				//verifica se a jogada desafio � possivel (so se a ultima carta jogada for comprar quatro)
				if (cartaAmostra.getClass() == ComprarQuatro.class) {
					return true;
				}
			} else if (tipoJogada == Jogo.TIPO_JOGADA_COMPRAR) {
				return true;
			} else if (tipoJogada == Jogo.TIPO_JOGADA_EMPRILHAR) {
				if (jogadorAtual.getBaralho().possui(carta) && cartaAmostra.ehEmpilhavel(carta)) {
					return true;
				}
			}
		}
		
		return false;
		
	}
	
	private void efetuarAcao(Carta carta) {
		
		jogadorAtual.getBaralho().retirarCarta(carta);
		
		if (carta.getClass() == ComprarQuatro.class) {
			
			cartasAcumuladas.addAll(pegarCartasMonteDisponivel(4));
			
		} if (carta.getClass() == ComprarDuas.class) {
			
			cartasAcumuladas.addAll(pegarCartasMonteDisponivel(2));
			//se o proximo jogador nao tiver +2, deve ser colocado em seu baralho as duas cartas
			//jogadorVez = proximoJogador();
			//caso tenha deve ser colocado no acumulador e passar para o próximo jogador;
			
			
		} else if (carta.getClass() == Inverter.class) {
			
			sentido = (-1) * sentido;
			
		} else if (carta.getClass() == Pular.class) {
			
			jogadorAtual = proximoJogador();
		}
			
		monteJogado.adicionaCarta(cartaAmostra);
		cartaJogadaAnterior = cartaAmostra;
		cartaAmostra = carta;
		
	}
	
	
	protected Jogador proximoJogador() {
		//sentido = 1
		//pega o jogador no �ndice posterior ao �ndice jogadorAtual
		
		//sentido = -1
		//pega o jogador no �ndice anterior ao �ndice jogadorAtual
		
		//pr�ximo �ndice
		indiceJogadorAnterior = indiceJogadorAtual;
		jogadorAnterior = jogadorAtual;
		
		indiceJogadorAtual += (sentido);
		
		//se pr�ximo �ndice n�o existir na lista, ele passa a ser o primeiro da lista (0)
		if (indiceJogadorAtual >= jogadores.size()) {
			indiceJogadorAtual = 0;
		} else if (indiceJogadorAtual < 0) {
			indiceJogadorAtual = jogadores.size() - 1;
		}

		//retorna o jogador na posi��o do �ndice
		jogadorAtual = jogadores.get(indiceJogadorAtual);
		return jogadorAtual;
	}
	
	protected void desfazerProximoJogador() {
		
		indiceJogadorAtual = indiceJogadorAnterior;
		jogadorAtual = jogadorAnterior;
		
		indiceJogadorAnterior += -1 * (sentido);
		
		
		//se pr�ximo �ndice n�o existir na lista, ele passa a ser o primeiro da lista (0)
		if (indiceJogadorAnterior >= jogadores.size()) {
			indiceJogadorAnterior = 0;
		} else if (indiceJogadorAnterior < 0) {
			indiceJogadorAnterior = jogadores.size() - 1;
		}

		//retorna o jogador na posi��o do �ndice
		jogadorAnterior = jogadores.get(indiceJogadorAnterior);
	}
	
	
/*	
	private Jogador jogadorVizinhoAnterior() {
		indiceJogadorAtual -= (sentido) * 1;
		
		//se pr�ximo �ndice n�o existir na lista, ele passa a ser o primeiro da lista (0)
		if (indiceJogadorAtual >= jogadores.size()) {
			indiceJogadorAtual = indiceJogadorAtual - jogadores.size();
		} else if (indiceJogadorAtual <= 0) {
			indiceJogadorAtual = jogadores.size() - 1;
		}

		//retorna o jogador na posi��o do �ndice
		return jogadores.get(indiceJogadorAtual);
	}
*/
	
	
	public void desistir(Jogador jogador) {
		jogadores.remove(jogador);
		
		monteJogado.adicionaCartas(jogador.getBaralho());
		
		if (jogadorAtual == jogador) {
			jogadorAtual = proximoJogador();
		}
	}
	
	
	protected boolean jogadaIlegal(Jogador jogador) {
		
		for (Carta carta : jogador.getBaralho().getCartas()) {
			if (!carta.ehMesmoTipo(cartaAmostra) && cartaJogadaAnterior.ehEmpilhavel(carta)) {
				return true;
			}
		}
		
		return false;
	}
	
}
